package com.peas.platform.module.icims.budget.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.framework.mybatisplus.domain.BaseDomain;
import com.peas.platform.framework.mybatisplus.po.BasePo;
import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;
import com.peas.platform.module.icims.base.approve.component.ApproveCallback;
import com.peas.platform.module.icims.base.approve.dto.ApproveDto;
import com.peas.platform.module.icims.base.approve.dto.ApproveOrderNodeDto;
import com.peas.platform.module.icims.base.approve.enums.ApproveOrderBusinessType;
import com.peas.platform.module.icims.base.approve.service.ApproveOrderService;
import com.peas.platform.module.icims.base.approve.service.ApproveService;
import com.peas.platform.module.icims.budget.apply.enums.BudgetCollectSync;
import com.peas.platform.module.icims.budget.archives.dto.BudgetKpiDto;
import com.peas.platform.module.icims.budget.archives.enums.KpiSource;
import com.peas.platform.module.icims.budget.archives.service.BudgetKpiService;
import com.peas.platform.module.icims.budget.project.api.req.SaveBudgetProjectTwoVo;
import com.peas.platform.module.icims.budget.project.api.req.SubmitBudgetProjectTwoVo;
import com.peas.platform.module.icims.budget.project.controller.vo.BudgetProjectTwoFileVo;
import com.peas.platform.module.icims.budget.project.controller.vo.BudgetProjectTwoItemVo;
import com.peas.platform.module.icims.budget.project.controller.vo.BudgetProjectTwoKpiVo;
import com.peas.platform.module.icims.budget.project.controller.vo.BudgetProjectTwoYearVo;
import com.peas.platform.module.icims.budget.project.domain.BudgetProjectTwoDomain;
import com.peas.platform.module.icims.budget.project.dto.*;
import com.peas.platform.module.icims.budget.project.enums.BudgetProjectTwoLibraryState;
import com.peas.platform.module.icims.budget.project.enums.BudgetProjectTwoState;
import com.peas.platform.module.icims.budget.project.enums.BudgetProjectTwoSync;
import com.peas.platform.module.icims.budget.project.service.*;
import com.peas.platform.module.icims.budget.ysy.service.BudgetYsyProjectTwoSyncService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class BudgetProjectTwoServiceImpl extends BaseServiceImpl<BudgetProjectTwoDto> implements BudgetProjectTwoService, ApproveCallback {

    @Value("${spring.profiles.active:local}")
    private String profiles;

    @Resource
    private BudgetProjectTwoDomain budgetBudgetProjectTwoDomain;
    @Resource
    private BudgetProjectTwoItemService projectTwoItemService;
    @Resource
    private BudgetProjectTwoYearService projectTwoYearService;
    @Resource
    private BudgetProjectTwoKpiService projectTwoKpiService;
    @Resource
    private BudgetProjectTwoFileService projectTwoFileService;
    @Resource
    private BudgetYsyProjectTwoSyncService budgetYsyProjectTwoSyncService;
    @Resource
    private ApproveService approveService;
    @Resource
    private ApproveOrderService approveOrderService;
    @Resource
    private BudgetKpiService budgetKpiService;

    @Override
    public BaseDomain<BudgetProjectTwoDto, ? extends BasePo> getDomain() {
        return budgetBudgetProjectTwoDomain;
    }

    @Transactional
    @Override
    public BudgetProjectTwoDto saveBudgetProjectTwo(SaveBudgetProjectTwoVo vo) {
        Assert.notEquals(vo.getYsySync(), BudgetProjectTwoSync.approved.getKey(), "项目[" + vo.getCode() + "]已经在预算域审批完成，无法修改");
        BudgetProjectTwoDto ptd = BeanUtil.copyProperties(vo, BudgetProjectTwoDto.class);
        if (StrUtil.isBlank(ptd.getState())) {
            ptd.setState(BudgetProjectTwoState.save.getKey());
        }
        ptd.setYsySync(BudgetProjectTwoSync.unsync.getKey());
        int result;
        if (ptd.getId() != null) {
            BudgetProjectTwoDto bean = this.getById(ptd.getId());
            BudgetProjectTwoState state = BaseEnum.key2Enum(BudgetProjectTwoState.class, bean.getState());
            Assert.isTrue(BudgetProjectTwoState.save == state || BudgetProjectTwoState.revocation == state || BudgetProjectTwoState.reject == state, "二级项目[" + bean.getCode() + "]的状态为[" + state.getKey() + "-" + state.getValue() + "]，不允许修改");
            result = this.updateById(ptd);
        } else {
            result = this.save(ptd);
        }
        Assert.isTrue(result > 0, "保存失败");
        List<BudgetProjectTwoItemDto> ptids = projectTwoItemService.listByField("projectTwoId", ptd.getId());
        projectTwoItemService.removeBatchByList(ptids);
        List<BudgetProjectTwoYearDto> ptyds = projectTwoYearService.listByField("projectTwoId", ptd.getId());
        projectTwoYearService.removeBatchByList(ptyds);
        List<BudgetProjectTwoKpiDto> ptkds = projectTwoKpiService.listByField("projectTwoId", ptd.getId());
        projectTwoKpiService.removeBatchByList(ptkds);
        List<BudgetProjectTwoFileDto> ptfds = projectTwoFileService.listByField("projectTwoId", ptd.getId());
        projectTwoFileService.removeBatchByList(ptfds);
        // items
        List<BudgetProjectTwoItemDto> ptidList = new ArrayList<>();
        CollUtil.forEach(vo.getItems(), (CollUtil.Consumer<BudgetProjectTwoItemVo>) (v, index) -> {
            BudgetProjectTwoItemDto dto = BeanUtil.copyProperties(v, BudgetProjectTwoItemDto.class);
            dto.setProjectTwoId(ptd.getId());
            ptidList.add(dto);
        });
        projectTwoItemService.saveBatch(ptidList);
        // years
        List<BudgetProjectTwoYearDto> ptydList = new ArrayList<>();
        CollUtil.forEach(vo.getYears(), (CollUtil.Consumer<BudgetProjectTwoYearVo>) (v, index) -> {
            BudgetProjectTwoYearDto dto = BeanUtil.copyProperties(v, BudgetProjectTwoYearDto.class);
            dto.setProjectTwoId(ptd.getId());
            ptydList.add(dto);
        });
        projectTwoYearService.saveBatch(ptydList);
        // kpis
        List<BudgetProjectTwoKpiVo> kpis = vo.getKpis();
        CollUtil.forEach(kpis, (CollUtil.Consumer<BudgetProjectTwoKpiVo>) (one, index1) -> {
            if (one.getParentId() == null) {
                BudgetProjectTwoKpiDto dto1 = BeanUtil.copyProperties(one, BudgetProjectTwoKpiDto.class);
                dto1.setProjectTwoId(ptd.getId());
                projectTwoKpiService.save(dto1);
                CollUtil.forEach(kpis, (CollUtil.Consumer<BudgetProjectTwoKpiVo>) (two, index2) -> {
                    if (two.getParentId() != null && two.getParentId().compareTo(one.getId()) == 0) {
                        BudgetProjectTwoKpiDto dto2 = BeanUtil.copyProperties(two, BudgetProjectTwoKpiDto.class);
                        dto2.setProjectTwoId(ptd.getId());
                        dto2.setParentId(dto1.getId());
                        projectTwoKpiService.save(dto2);
                        CollUtil.forEach(kpis, (CollUtil.Consumer<BudgetProjectTwoKpiVo>) (three, index3) -> {
                            if (three.getParentId() != null && three.getParentId().compareTo(two.getId()) == 0) {
                                BudgetProjectTwoKpiDto dto3 = BeanUtil.copyProperties(three, BudgetProjectTwoKpiDto.class);
                                dto3.setProjectTwoId(ptd.getId());
                                dto3.setParentId(dto2.getId());
                                if (StrUtil.isBlank(dto3.getKpiCode())) {
                                    BudgetKpiDto kpi = budgetKpiService.addBudgetKpi(KpiSource.projectTwo, dto3.getKpiName(), two.getId(), dto3.getWeight());
                                    if (kpi != null)
                                        dto3.setKpiCode(kpi.getCode());
                                }
                                projectTwoKpiService.save(dto3);
                            }
                        });
                    }
                });
            }
        });
        // files
        List<BudgetProjectTwoFileDto> ptfdList = new ArrayList<>();
        CollUtil.forEach(vo.getFiles(), (CollUtil.Consumer<BudgetProjectTwoFileVo>) (v, index) -> {
            BudgetProjectTwoFileDto dto = BeanUtil.copyProperties(v, BudgetProjectTwoFileDto.class);
            dto.setProjectTwoId(ptd.getId());
            ptfdList.add(dto);
        });
        projectTwoFileService.saveBatch(ptfdList);
        return ptd;
    }

    @Transactional
    @Override
    public void submitBudgetProjectTwo(SubmitBudgetProjectTwoVo vo) {
        Assert.notNull(vo.getApproveId(), "请选择审批模版");
        SaveBudgetProjectTwoVo v = BeanUtil.copyProperties(vo, SaveBudgetProjectTwoVo.class);
        v.setState(BudgetProjectTwoState.submit.getKey());
        v.setItems(vo.getItems());
        v.setKpis(vo.getKpis());
        BudgetProjectTwoDto bod = this.saveBudgetProjectTwo(v);
        ApproveDto ad = approveService.getById(vo.getApproveId());
        approveOrderService.createApproveOrder(ad, BeanUtil.copyToList(vo.getApproveNodes(), ApproveOrderNodeDto.class), ApproveOrderBusinessType.budgetProjectTwo, bod.getId(), bod.getCode(), null, this.getClass());
    }

    @Transactional
    @Override
    public void revocationBudgetProjectTwo(Long id) {
        BudgetProjectTwoDto dto = this.getById(id);
        Assert.notNull(dto, "找不到二级项目");
        dto.setState(BudgetProjectTwoState.revocation.getKey());
        this.updateById(dto);
        approveOrderService.revocationApproveOrder(ApproveOrderBusinessType.budgetProjectTwo, id);
    }

    @Transactional
    @Override
    public void syncBudgetProjectTwo(Long id) {
        BudgetProjectTwoDto ptd = this.getById(id);
        Assert.equals(ptd.getYsySync(), BudgetCollectSync.unsync.getKey(), "只有[{}]的二级项目才能操作", BudgetCollectSync.unsync.getValue());
        ptd.setYsySync("1");
        this.updateById(ptd);
        if (StrUtil.equals("production", profiles)) {
            List<BudgetProjectTwoItemDto> ptids = projectTwoItemService.listByField("projectTwoId", ptd.getId());
            List<BudgetProjectTwoYearDto> ptyds = projectTwoYearService.listByField("projectTwoId", ptd.getId());
            List<BudgetProjectTwoKpiDto> ptkds = projectTwoKpiService.listByField("projectTwoId", ptd.getId());
            List<BudgetProjectTwoFileDto> ptfds = projectTwoFileService.listByField("projectTwoId", ptd.getId());
            budgetYsyProjectTwoSyncService.syncBudgetProjectTwo(ptd, ptids, ptyds, ptkds, ptfds);
        }
    }

    @Transactional
    @Override
    public void callbackAfterApprove(Long businessId, boolean isPass, boolean isFinalPass) {
        if (businessId == null)
            return;
        if (isPass) {
            if (isFinalPass) {
                BudgetProjectTwoDto bod = this.getById(businessId);
                bod.setState(BudgetProjectTwoState.pass.getKey());
                bod.setLibraryState(BudgetProjectTwoLibraryState.alternative.getKey());
                this.updateById(bod);
            }
        } else {
            BudgetProjectTwoDto bod = this.getById(businessId);
            bod.setState(BudgetProjectTwoState.reject.getKey());
            this.updateById(bod);
        }
    }

}
